// 版权归陈超所有


#include "Player/CC_PlayerController.h"

#include "AbilitySystemBlueprintLibrary.h"
#include "AbilitySystem/CC_AbilitySystemComponent.h"
#include "CC_GameplayTags.h"
#include "Components/SplineComponent.h"
#include "EnhancedInputSubsystems.h"
#include "EnhancedInputComponent.h"
#include "NavigationPath.h"
#include "NavigationSystem.h"
#include "Input/CC_InputComponent.h"
#include "Interations/CC_EnemyInterface.h"

ACC_PlayerController::ACC_PlayerController()
{
	bReplicates = true;		//确保可复制
	
	Spline = CreateDefaultSubobject<USplineComponent>("Spline");
	
}

void ACC_PlayerController::PlayerTick(float DeltaTime)
{
	Super::PlayerTick(DeltaTime);
	CurserTrace();
	AutoRun();
}

void ACC_PlayerController::AutoRun()
{
	if(!bAutoRunning) return;
	
	APawn* ControlledPawn = GetPawn();
	if(ControlledPawn == nullptr) return;
	
	//找到距离样条最近的位置
	const FVector LocationOnSpline = Spline->FindLocationClosestToWorldLocation(ControlledPawn->GetActorLocation(), ESplineCoordinateSpace::World);
	//获取这个位置在样条上的方向
	const FVector Direction = Spline->FindDirectionClosestToWorldLocation(LocationOnSpline, ESplineCoordinateSpace::World);
	ControlledPawn->AddMovementInput(Direction);

	const float DistanceToDestination = (LocationOnSpline - CachedDestination).Length();
	if(DistanceToDestination <= AutoRunAcceptanceRadius)
	{
		bAutoRunning = false;
	}
}

//鼠标位置追踪
void ACC_PlayerController::CurserTrace()
{
	GetHitResultUnderCursor(ECC_Visibility, false, CursorHit);	//获取可视的鼠标命中结果
	if(!CursorHit.bBlockingHit) return; //如果未命中直接返回

	LastActor = ThisActor;
	ThisActor = CursorHit.GetActor();
	
	if (LastActor != ThisActor)
	{
		if (LastActor) LastActor->UnHighlightActor();
		if (ThisActor) ThisActor->HighlightActor();
	}
}


void ACC_PlayerController::BeginPlay()
{
	Super::BeginPlay();

	//设置鼠标光标
	bShowMouseCursor = true; //游戏中是否显示鼠标光标
	DefaultMouseCursor = EMouseCursor::Default; //鼠标光标的样式

	FInputModeGameAndUI InputModeData;
	InputModeData.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock); //将鼠标锁定在视口内
	InputModeData.SetHideCursorDuringCapture(false); //鼠标被捕获时是否隐藏
	SetInputMode(InputModeData); //设置给控制器

}

UCC_AbilitySystemComponent* ACC_PlayerController::GetCC_AbilitySystemComponent()
{
	if (CC_AbilitySystemComponent == nullptr)
	{
		UAbilitySystemComponent* AbilitySystemComponent = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(GetPawn<APawn>());
		CC_AbilitySystemComponent = Cast<UCC_AbilitySystemComponent>(AbilitySystemComponent);
	}
	return CC_AbilitySystemComponent;
}

//设置输入组件函数（重载）
void ACC_PlayerController::SetupInputComponent()
{
	Super::SetupInputComponent();

	checkf(DataAssetInputConfig,TEXT("DataAssetInputConfig 指针为空！"));
	
	UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer());
	if(Subsystem == nullptr) return;
	//添加映射上下文
	Subsystem->AddMappingContext(DataAssetInputConfig->DefaultMappingContext, 0);
	
	UCC_InputComponent* CC_InputComponent = CastChecked<UCC_InputComponent>(InputComponent); //将InputComponent转换成增强输入组件

	CC_InputComponent->BindInputAction(DataAssetInputConfig, CC_GameplayTags::Input_Move, ETriggerEvent::Triggered, this, &ThisClass::Move); //绑定移动事件
	CC_InputComponent->BindAbilityAction(DataAssetInputConfig, this, &ThisClass::AbilityInputTagPressed, &ThisClass::AbilityInputTagReleased, &ThisClass::AbilityInputTagHold);
}

//移动事件的返回函数
void ACC_PlayerController::Move(const struct FInputActionValue& InputActionValue)
{
	const FVector2D InputAxisVector = InputActionValue.Get<FVector2D>(); //获取输入操作的2维向量值
	const FRotator Rotation = GetControlRotation(); //获取控制器旋转
	const FRotator YawRotation(0.f, Rotation.Yaw, 0.f); //通过控制器的垂直朝向创建一个旋转值，忽略上下朝向和左右朝向

	const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X); //获取向前的值(旋转矩阵)
	const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y); //获取向右的值，-1到1

	if(APawn* ControlledPawn = GetPawn<APawn>())
	{
		ControlledPawn->AddMovementInput(ForwardDirection, InputAxisVector.Y);
		ControlledPawn->AddMovementInput(RightDirection, InputAxisVector.X);
	}
	
}

/*开始按下*/
void ACC_PlayerController::AbilityInputTagPressed(FGameplayTag InputTag)
{
	/*如果是鼠标左键*/
	if (InputTag.MatchesTagExact(CC_GameplayTags::Input_LMB))
	{
		bTargetting = ThisActor ? true : false;		//是否有敌人?
		bAutoRunning = false;		//不需要自动追踪
	}
}

/*释放*/
void ACC_PlayerController::AbilityInputTagReleased(FGameplayTag InputTag)
{
	/*如果不是鼠标左键*/
	if (!InputTag.MatchesTagExact(CC_GameplayTags::Input_LMB))
	{
		if (GetCC_AbilitySystemComponent() == nullptr) return;
		GetCC_AbilitySystemComponent()->AbilityInputTagReleased(InputTag);
		return;
	}
	
	/*如果是鼠标左键*/
	if (bTargetting)	//是敌人类
	{
		if (GetCC_AbilitySystemComponent() == nullptr) return;
		GetCC_AbilitySystemComponent()->AbilityInputTagReleased(InputTag);
		return;
	}
	
	if(FollowTime > ShortPressThreshold)	return;		//长按,退出
	
	/*短按*/
	APawn* ControlledPawn = GetPawn();
	if (ControlledPawn == nullptr) return;
	
	/*同步查找路径位置*/
	UNavigationPath* NavPath = UNavigationSystemV1::FindPathToLocationSynchronously(this, ControlledPawn->GetActorLocation(), CachedDestination);
	if (NavPath == nullptr) return;

	Spline->ClearSplinePoints(); //清除样条内现有的点
	for(const FVector& PointLoc : NavPath->PathPoints)
	{
		Spline->AddSplinePoint(PointLoc, ESplineCoordinateSpace::World); //将新的位置添加到样条曲线中
		DrawDebugSphere(GetWorld(), PointLoc, 8.f, 8, FColor::Cyan, false, 5.f); //点击后debug调试
	}
	//自动寻路将最终目的地设置为导航的终点，方便停止导航
	if (NavPath->PathPoints.Num() > 0)
	{
		CachedDestination = NavPath->PathPoints[NavPath->PathPoints.Num() - 1];
	}
	
	bAutoRunning = true; //设置当前正常自动寻路状态，将在tick中更新位置
	FollowTime = 0.f;
	bTargetting = false;
}

/*保持*/
void ACC_PlayerController::AbilityInputTagHold(FGameplayTag InputTag)
{
	/*如果不是鼠标左键*/
	if (!InputTag.MatchesTagExact(CC_GameplayTags::Input_LMB))
	{
		if (GetCC_AbilitySystemComponent() == nullptr) return;
		GetCC_AbilitySystemComponent()->AbilityInputTagHeld(InputTag);
		return;
	}
	/*如果是鼠标左键*/
	if (bTargetting)	//是敌人类
	{
		if (GetCC_AbilitySystemComponent() == nullptr) return;
		GetCC_AbilitySystemComponent()->AbilityInputTagHeld(InputTag);
		return;
	}
						//非敌人类
	FollowTime += GetWorld()->GetDeltaSeconds();
	
	if (CursorHit.bBlockingHit)		//阻挡性碰撞
	{
		CachedDestination = CursorHit.ImpactPoint;		//缓存点击位置
	}
	
	if (APawn* ControlledPawn = GetPawn<APawn>())
	{
		const FVector WorldDirection = (CachedDestination - ControlledPawn->GetActorLocation()).GetSafeNormal();
		ControlledPawn->AddMovementInput(WorldDirection);
	}
	if(!bAutoRunning) FollowTime = 0.f;
}



